package main

import (
	"fmt"
	"reflect"
)

type Student struct {
	Name   string `json:"name"`
	Age    int    `json:"age"`
	MScore MScore `json:"math"`
	EScore EScore `json:"english"`
	Score4 int    `json:"score" mtype:"4"`
}

type MScore struct {
	Score1 int `mtype:"1"`
}

type EScore struct {
	Score2 int `mtype:"2"`
	SScore SScore
}

type SScore struct {
	Score3 int `mtype:"3"`
}

type Interface interface {
	Get()
}

type I1 struct {
	v int
}

func (this *I1) Get() {}

type T2 struct {
	V1 *int
	V2 *int
}

func main() {
	var Var float64 = 3.14
	fmt.Println(reflect.TypeOf(Var), reflect.ValueOf(Var))

	var Stu Student = Student{"Astone", 21, MScore{98}, EScore{99, SScore{100}}, 2}
	fmt.Println(reflect.TypeOf(Stu), reflect.ValueOf(Stu), reflect.TypeOf(&Stu.Name))
	reflect.ValueOf(&Stu).Elem().FieldByName("Age").SetInt(23)
	reflect.ValueOf(&Stu).Elem().FieldByName("Name").SetString("Astones")
	fmt.Println(reflect.ValueOf(&Stu).Elem().FieldByName("Name").String(), reflect.ValueOf(&Stu).Elem().FieldByName("Age").Int())

	finder := NewTagFinder(&Student{}, "mtype")
	fmt.Println(finder.path)
	fmt.Println(finder.GetInt(&Stu, "1"), finder.GetInt(&Stu, "2"), finder.GetInt(&Stu, "3"), finder.GetInt(&Stu, "4"))

	Elem := reflect.ValueOf(&Stu).Elem()
	for i := 0; i < Elem.NumField(); i++ {
		fmt.Printf("%d: %s %s = %v\n", i, Elem.Type().Field(i).Name, Elem.Field(i).Type(), Elem.Field(i).Interface())
	}
	f0 := Elem.Field(1)
	Stu.Age = 24
	fmt.Println(f0.Interface())

	Type := reflect.TypeOf(&Stu).Elem()
	for i := 0; i < Type.NumField(); i++ {
		fmt.Printf("%s, %s\n", Type.Field(i).Tag, reflect.StructTag(Type.Field(i).Tag).Get("json"))
	}

	v1 := &Stu.Name
	val := reflect.ValueOf(&Stu)
	ind := reflect.Indirect(val)
	v2 := ind.Field(0).Addr().Interface()

	fmt.Println(reflect.TypeOf(v1))
	fmt.Println(reflect.TypeOf(v2))

	// interface
	var i Interface
	i = (*I1)(nil)
	fmt.Println(reflect.TypeOf(i))
	v := reflect.New(reflect.TypeOf(i).Elem()).Interface()
	c := v.(*I1)
	c.v = 1
	fmt.Println(c, reflect.TypeOf(i))

	// reflect.New
	{
		fmt.Println("reflect.New")
		t := &T2{}
		m := reflect.ValueOf(t).Elem()
		for i := 0; i < m.NumField(); i++ {
			//m.Field(i).Set(reflect.New(reflect.TypeOf(m.Field(i).Interface()).Elem()))
			m.Field(i).Set(reflect.New(m.Field(i).Type().Elem()))
			v := m.Field(i).Interface()
			switch val := v.(type) {
			case *int:
				(*val) = i + 100
			}
		}
		fmt.Println(*t.V1, *t.V2)
		fmt.Println("reflect.New")
	}

	fmt.Println("ExampleMakeType")
	ExampleMakeType()
}
